/**
 * 实现new方法 
 * new 过程
 * 1、创建一个新对象
 * 2、将构造函数的this赋值给新对象
 * 3、执行构造函数（给新对象添加属性）
 * 4、返回新对象
 */

function _new_ (fn, ...arg) {
  const obj = Object.create(fn.prototype);  //  Object.create 方法创建的是对对象的引用，没有创建一个空间
  const newObj = fn.apply(obj, arg);
  return newObj instanceof Object ? newObj : obj;
}


function create (Con, ...args) {
  let obj = {}
  Object.setPrototypeOf(obj, Con.prototype)
  let result = Con.apply(obj, args)
  return result instanceof Object ? result : obj
}


function _create () {  // 类似上面 _new_
  // 1. 获取构造函数，并且删除 arguments 中的第一项
  var Con = [].shift.call(arguments);
  // 2. 创建一个空的对象并链接到构造函数的原型，使它能访问原型中的属性
  var obj = Object.create(Con.prototype);
  // 3. 使用apply改变构造函数中this的指向实现继承，使obj能访问到构造函数中的属性
  var ret = Con.apply(obj, arguments);
  // 4. 优先返回构造函数返回的对象
  return ret instanceof Object ? ret : obj;
}


function _new (constructor, ...args) {
  // 构造函数类型合法判断
  if (typeof constructor !== 'function') {
    throw new Error('constructor must be a function');
  }
  // 新建空对象实例
  let obj = new Object();
  // 将构造函数的原型绑定到新创的对象实例上
  obj.__proto__ = Object.create(constructor.prototype);
  // 等价 Object.setProtypeOf(obj,constructor.prototype)
  // 调用构造函数并判断返回值
  let res = constructor.apply(obj, args);
  let isObject = typeof res === 'object' && res !== null;
  let isFunction = typeof res === 'function';
  // 如果有返回值且返回值是对象类型，那么就将它作为返回值，否则就返回之前新建的对象
  return isObject || isFunction ? res : obj;
};


/** 以上方法实现可以用来创建自定义类的实例，但不支持内置对象，毕竟new属于操作符，底层实现更加复杂。*/
